/* global viewer Cesium */
import 'leaflet';
import { wkt } from '@mapbox/leaflet-omnivore';
import axios from 'axios';
import { getImgBase64 } from 'S/interface';
import { simplify, getCoords, featureEach, bbox } from '@turf/turf';

const constant = 57.29577951308232;
const dataJson = {
    checkedMap: [],
    checkedSheetMap: [],
    currentPageData: [],
    cancelTokenObj: {},
};

let canvas = document.createElement('canvas');
canvas.width = 1800;
canvas.height = 900;
let context = canvas.getContext('2d');

function translationPoint(position, duration, distance) {
    let p = new Cesium.Cartographic(
        Cesium.Math.toRadians(position[0]),
        Cesium.Math.toRadians(position[1]),
        0
    );
    let d = new Cesium.Cartographic(
        Cesium.Math.toRadians(position[0] + duration[0]),
        Cesium.Math.toRadians(position[1] + duration[1]),
        0
    );
    return new Cesium.EllipsoidGeodesic(p, d).interpolateUsingSurfaceDistance(distance);
}

function drawGeoJson(geojson) {
    context.clearRect(0, 0, canvas.width, canvas.height);
    let holes = [];
    let style = {
        fill: true,
        fillColor: 'rgba(41,131,231,0.3)',
    };
    function drawFeature(currentFeature) {
        context.fillStyle = style.fillColor;

        if (currentFeature.geometry.type === 'Polygon') {
            let contours = getCoords(currentFeature);
            let tempHoles = drawContours(context, contours);
            if (tempHoles) {
                tempHoles.forEach(hole => {
                    hole.style = style;
                    holes.push(hole);
                });
            }
        } else if (currentFeature.geometry.type === 'MultiPolygon') {
            let polygons;
            try {
                polygons = getCoords(currentFeature);
                polygons.forEach(function(contours) {
                    let tempHoles = drawContours(context, contours);
                    if (tempHoles.length > 0) {
                        tempHoles.forEach(function(hole) {
                            hole.style = style;
                            holes.push(hole);
                        });
                    }
                });
            } catch (e) {
                console.log(e);
            }
        }
    }

    featureEach(geojson, function(fc) {
        if (fc.geometry.type === 'Polygon' || fc.geometry.type === 'MultiPolygon') {
            drawFeature(fc);
        }
    });
    if (holes && holes.length) {
        createHoles(context, holes);
    }
}
// 绘制多边形（面或线）
function drawContours(context, contours) {
    let holes = [];
    contours.forEach(function(contour, index) {
        if (index < 1) {
            context.beginPath();
            let exceedingP = [];
            let bool1 = false;
            let bool2 = false;
            contour.forEach(function(coordinate, pointIndex, arr) {
                if (bool1) {
                    exceedingP[exceedingP.length - 1].push([
                        ((coordinate[0] - 180) / 360) * canvas.width,
                        canvas.height - ((coordinate[1] + 90) / 180) * canvas.height,
                    ]);
                    bool1 = coordinate[0] > 180;
                }
                if (coordinate[0] > 180 && !bool1 && pointIndex !== 0) {
                    exceedingP.push([]);
                    bool1 = true;
                    exceedingP[exceedingP.length - 1].push([
                        ((arr[pointIndex - 1][0] - 180) / 360) * canvas.width,
                        canvas.height - ((arr[pointIndex - 1][1] + 90) / 180) * canvas.height,
                    ]);
                    exceedingP[exceedingP.length - 1].push([
                        ((coordinate[0] - 180) / 360) * canvas.width,
                        canvas.height - ((coordinate[1] + 90) / 180) * canvas.height,
                    ]);
                }

                if (bool2) {
                    exceedingP[exceedingP.length - 1].push([
                        ((coordinate[0] + 540) / 360) * canvas.width,
                        canvas.height - ((coordinate[1] + 90) / 180) * canvas.height,
                    ]);
                    bool2 = coordinate[0] < -180;
                }
                if (coordinate[0] < -180 && !bool2 && pointIndex !== 0) {
                    exceedingP.push([]);
                    bool2 = true;
                    exceedingP[exceedingP.length - 1].push([
                        ((arr[pointIndex - 1][0] + 540) / 360) * canvas.width,
                        canvas.height - ((arr[pointIndex - 1][1] + 90) / 180) * canvas.height,
                    ]);
                    exceedingP[exceedingP.length - 1].push([
                        ((coordinate[0] + 540) / 360) * canvas.width,
                        canvas.height - ((coordinate[1] + 90) / 180) * canvas.height,
                    ]);
                }

                let pt = {
                    x: ((coordinate[0] + 180) / 360) * canvas.width,
                    y: canvas.height - ((coordinate[1] + 90) / 180) * canvas.height,
                };
                if (pointIndex !== 0) {
                    context.lineTo(pt.x, pt.y);
                } else {
                    context.moveTo(pt.x, pt.y);
                }
            });
            context.closePath();
            context.fill();

            if (exceedingP.length > 0) {
                drawExceedingArea(context, exceedingP);
            }
        } else {
            holes.push(contour);
        }
    });
    return holes;
}
function drawExceedingArea(context, exceedingP) {
    exceedingP.forEach(function(contour) {
        context.beginPath();
        contour.forEach(function(coordinate, pointIndex) {
            if (pointIndex === 0) {
                context.moveTo(coordinate[0], coordinate[1]);
            } else {
                context.lineTo(coordinate[0], coordinate[1]);
            }
        });
        context.closePath();
        context.fill();
    });
}
/**
 * 挖孔
 */
function createHoles(context, holes) {
    let tileCanvas = context.canvas;
    let imgData = context.getImageData(0, 0, tileCanvas.width, tileCanvas.height);

    let holeMaskCanvas = document.createElement('canvas');
    holeMaskCanvas.width = tileCanvas.width;
    holeMaskCanvas.height = tileCanvas.height;
    let holeMaskCtx = holeMaskCanvas.getContext('2d');

    let mask = [];
    holes.forEach(function(hole) {
        holeMaskCtx.clearRect(0, 0, holeMaskCanvas.width, holeMaskCanvas.height);
        holeMaskCtx.beginPath();
        let pointIndex = 0;

        hole.forEach(function(coordinate) {
            let pt = {
                x: ((coordinate[0] + 180) / 360) * canvas.width,
                y: canvas.height - ((coordinate[1] + 90) / 180) * canvas.height,
            };
            if (pointIndex === 0) {
                holeMaskCtx.moveTo(pt.x, pt.y);
            } else {
                holeMaskCtx.lineTo(pt.x, pt.y);
            }
            pointIndex++;
        });
        holeMaskCtx.closePath();

        holeMaskCtx.fillStyle = 'rgba(41,131,231,0.3)';
        holeMaskCtx.fill();
        mask = holeMaskCtx.getImageData(0, 0, holeMaskCanvas.width, holeMaskCanvas.height).data;
        for (let i = 3; i < mask.length; i += 4) {
            if (mask[i] > 0) {
                imgData.data[i] = 0;
            }
        }
    });
    context.putImageData(imgData, 0, 0);
}

/**
 * 设置偏转角度
 * @param {Array}   positions   需要计算的点数组;格式[[lon, lat],[lon, lat]]
 */
function calculateAngle(positions) {
    // 弧度
    let Radian = 0;
    // 角度
    let Angle = 0;
    let x = positions[1][0] - positions[0][0];
    let y = positions[1][1] - positions[0][1];
    if (!(x === 0 && y === 0)) {
        if (y >= 0) {
            Radian = Math.asin(x / Math.sqrt(x * x + y * y));
            Angle = (-Radian * 180) / Math.PI;
        } else if (x !== 0) {
            Radian = Math.asin(x / Math.sqrt(x * x + y * y));
            Angle = (Radian * 180) / Math.PI - 180;
        } else {
            Radian = Math.acos(y / Math.sqrt(x * x + y * y));
            Angle = (Radian * 180) / Math.PI + (90 * Radian) / Math.abs(Radian);
        }
    }
    return Angle;
}

function positionsHandle(data) {
    return Cesium.Cartesian3.fromDegreesArray([
        Number(data.bottomleftlongitude),
        Number(data.bottomleftlatitude),
        Number(data.bottomrightlongitude),
        Number(data.bottomrightlatitude),
        Number(data.toprightlongitude),
        Number(data.toprightlatitude),
        Number(data.topleftlongitude),
        Number(data.topleftlatitude),
        Number(data.bottomleftlongitude),
        Number(data.bottomleftlatitude),
    ]);
}

export default {
    addTarget(point) {
        this.clearToolArea();
        if (!point) return;
        point = point
            .replace('POINT (', '')
            .replace(')', '')
            .split(' ');

        let position = Cesium.Cartesian3.fromDegrees(Number(point[0]), Number(point[1]));
        let east = translationPoint([Number(point[0]), Number(point[1])], [1, 0], 10000).longitude;
        let north = translationPoint([Number(point[0]), Number(point[1])], [0, 1], 10000).latitude;
        let south = translationPoint([Number(point[0]), Number(point[1])], [0, -1], 10000).latitude;
        let west = translationPoint([Number(point[0]), Number(point[1])], [-1, 0], 10000).longitude;
        let positions = Cesium.Cartesian3.fromRadiansArray([
            east,
            north,
            east,
            south,
            west,
            south,
            west,
            north,
            east,
            north,
        ]);

        this.createTarget(position, positions, 10000 * Math.pow(2, 0.5), 'static/img/place.png');
        return [
            {
                longitude: east * constant,
                latitude: north * constant,
                height: 0,
            },
            {
                longitude: east * constant,
                latitude: south * constant,
                height: 0,
            },
            {
                longitude: west * constant,
                latitude: south * constant,
                height: 0,
            },
            {
                longitude: west * constant,
                latitude: north * constant,
                height: 0,
            },
        ];
        // return `POLYGON((${east*constant} ${north*constant},${east*constant} ${south*constant},${west*constant} ${south*constant},${west*constant} ${north*constant},${east*constant} ${north*constant}))`
    },

    createTarget(position, positions, radius, img) {
        viewer.entities.removeById('target');
        viewer.entities.add({
            id: 'target',
            position: position,
            billboard: {
                image: img,
                horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
                verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
                heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
                distanceDisplayCondition: new Cesium.DistanceDisplayCondition(radius * 300),
            },
            polyline: {
                positions: positions,
                arcType: Cesium.ArcType.RHUMB,
                width: 3,
                material: Cesium.Color.fromCssColorString('rgba(253, 128, 69, 1.0)'),
                clampToGround: true,
                classificationType: Cesium.ClassificationType.TERRAIN,
                distanceDisplayCondition: new Cesium.DistanceDisplayCondition(0, radius * 300),
            },
            leftClick: function(entity) {
                viewer.zoomTo(entity, new Cesium.HeadingPitchRange(0, -Math.PI / 2, radius * 10));
            },
        });
    },
    createDataArea(data, id) {
        let entity = null;
        id = id || 'dataArea';
        if (!data) return;
        dataJson[id] = dataJson[id] || [];

        let geo = wkt.parse(data).toGeoJSON();
        geo = simplify(geo, { tolerance: 0.01, mutate: true });
        drawGeoJson(geo);
        viewer.entities.add({
            id: id,
            rectangle: {
                coordinates: Cesium.Rectangle.fromDegrees(-180.0, -90.0, 180.0, 90.0),
                material: canvas,
                zIndex: 1,
            },
        });
        let color = Cesium.Color.fromCssColorString('#2983e7');
        Cesium.GeoJsonDataSource.load(geo).then(dataSource => {
            for (let i = 0; i < dataSource.entities.values.length; ++i) {
                entity = dataSource.entities.values[i];
                if (!entity.polygon) continue;
                dataJson[id].push(
                    viewer.entities.add({
                        polyline: {
                            arcType: Cesium.ArcType.RHUMB,
                            positions: [
                                ...entity.polygon.hierarchy._value.positions,
                                entity.polygon.hierarchy._value.positions[0],
                            ],
                            width: 3,
                            material: color,
                            clampToGround: true,
                            classificationType: Cesium.ClassificationType.TERRAIN,
                            zIndex: 1,
                        },
                    })
                );
                let holes = entity.polygon.hierarchy._value.holes;
                for (let j = 0; j < holes.length; ++j) {
                    dataJson[id].push(
                        viewer.entities.add({
                            polyline: {
                                positions: [...holes[j].positions, holes[j].positions[0]],
                                arcType: Cesium.ArcType.RHUMB,
                                width: 3,
                                clampToGround: true,
                                material: color,
                                classificationType: Cesium.ClassificationType.TERRAIN,
                                zIndex: 1,
                            },
                        })
                    );
                }
            }
            dataSource = null;
        });
        return geo;
    },
    removeLayer(id) {
        id = id || 'dataArea';
        if (dataJson[id] && dataJson[id].length > 0) {
            dataJson[id].forEach(item => {
                viewer.entities.remove(item);
            });
            dataJson[id].length = 0;
        }
        // viewer.dataSources.remove(dataJson[id]);
        viewer.entities.removeById(id);
    },
    /**
     * 显示当前页数据范围
     * @param {Array}  items     当前页数据
     */
    createCurrentDataArea(items) {
        let entity = null;

        for (let i = 0; i < dataJson.currentPageData.length; ++i) {
            viewer.entities.removeById(dataJson.currentPageData[i]);
        }
        dataJson.currentPageData.length = 0;

        for (let i = 0; i < items.length; ++i) {
            let id = items[i].sateidAndsensorid + items[i].productid;
            entity = viewer.entities.getById(id);
            if (entity) return;
            let positions = positionsHandle(items[i]);
            viewer.entities.add({
                id: id,
                polyline: {
                    positions: positions,
                    arcType: Cesium.ArcType.RHUMB,
                    width: 3,
                    material: Cesium.Color.YELLOW,
                    clampToGround: true,
                    classificationType: Cesium.ClassificationType.TERRAIN,
                    zIndex: 5,
                },
            });
            dataJson.currentPageData.push(id);
        }
    },

    /**
     * 显示当前页数据范围
     * @param {Array}  items     当前页数据
     */
    createWKTArea(items) {
        let entity = null;

        for (let i = 0; i < dataJson.currentPageData.length; ++i) {
            viewer.entities.removeById(dataJson.currentPageData[i]);
        }
        dataJson.currentPageData.length = 0;

        for (let i = 0; i < items.length; ++i) {
            let id = items[i].gid;
            entity = viewer.entities.getById(id);
            if (entity) return;
            let positions = items[i].geom
                .replace('MULTIPOLYGON(((', '')
                .replace(')))', '')
                .split(',');
            for (let i = 0; i < positions.length; ++i) {
                let p = positions[i].split(' ');
                positions[i] = Cesium.Cartesian3.fromDegrees(Number(p[0]), Number(p[1]));
            }
            viewer.entities.add({
                id: id,
                polyline: {
                    positions: positions,
                    width: 3,
                    arcType: Cesium.ArcType.RHUMB,
                    material: Cesium.Color.YELLOW,
                    clampToGround: true,
                    classificationType: Cesium.ClassificationType.TERRAIN,
                    zIndex: 5,
                },
            });
            dataJson.currentPageData.push(id);
        }
    },
    currentItem(item, flag) {
        let entity = viewer.entities.getById(item);
        if (entity) {
            entity.polyline.material = flag ? Cesium.Color.RED : Cesium.Color.YELLOW;
            entity.polyline.zIndex = flag ? 10 : 5;
        }
    },
    /**
     * 相机对位
     * @param {Array}   positions   目标的坐标数组
     * @param {Number}  scale       相机移动距离半数，默认为10
     */
    flyToBoundingSphere(positions, scale = 10) {
        if (!positions || positions.length < 1) return;
        let boundingSphere = Cesium.BoundingSphere.fromPoints(positions);
        viewer.camera.flyToBoundingSphere(boundingSphere, {
            offset: new Cesium.HeadingPitchRange(0, -Math.PI / 2, boundingSphere.radius * scale),
        });
    },
    positioning(id, height) {
        if (!height) {
            height = 2000000;
        }
        let entity = viewer.entities.getById(id);
        viewer.camera.flyToBoundingSphere(
            Cesium.BoundingSphere.fromPoints(entity.polyline.positions._value),
            {
                offset: new Cesium.HeadingPitchRange(0, -Math.PI / 2, height),
            }
        );
    },
    positioningLatLngArr(latLngArr, height) {
        if (!latLngArr || latLngArr.length < 1) return;
        if (!height) {
            height = 2000000;
        }
        viewer.camera.flyToBoundingSphere(Cesium.BoundingSphere.fromPoints(latLngArr), {
            offset: new Cesium.HeadingPitchRange(0, -Math.PI / 2, height),
        });
    },

    /**
     * 设置影像是否加载
     * @param {Object}  data     影像数据
     * @param {Boolean} flag    是否加载
     */
    checkChange(data, flag) {
        let id = data.sateidAndsensorid + data.productid + '_check';
        let index = dataJson.checkedMap.indexOf(id);
        if (index === -1 && flag) {
            let rotation = calculateAngle([
                [Number(data.bottomrightlongitude), Number(data.bottomrightlatitude)],
                [Number(data.toprightlongitude), Number(data.toprightlatitude)],
            ]);

            let positions = positionsHandle(data);

            let param = {
                param: { url: data.browsefilelocation },
                cancelToken: new axios.CancelToken(function executor(c) {
                    dataJson.cancelTokenObj[data.thumbimg] = c;
                }),
            };
            getImgBase64(param)
                .then(res => {
                    delete dataJson.cancelTokenObj[data.browsefilelocation];
                    viewer.entities.add({
                        id: id,
                        polyline: {
                            positions: positions,
                            width: 2,
                            arcType: Cesium.ArcType.RHUMB,
                            material: Cesium.Color.YELLOW,
                        },
                        polygon: {
                            arcType: Cesium.ArcType.RHUMB,
                            hierarchy: positions,
                            material: res.data,
                            stRotation: (-rotation * Math.PI) / 180,
                            classificationType: Cesium.ClassificationType.TERRAIN,
                            zIndex: 5,
                        },
                    });
                })
                .catch(e => {});
            dataJson.checkedMap.push(id);
        }
        if (index !== -1 && !flag) {
            viewer.entities.removeById(id);
            dataJson.checkedMap.splice(index, 1);
        }
        if (dataJson.cancelTokenObj[data.browsefilelocation] && !flag) {
            dataJson.cancelTokenObj[data.browsefilelocation]();
            delete dataJson.cancelTokenObj[data.browsefilelocation];
        }
    },
    setZIndex(id) {
        viewer.entities.getById(id).polygon.zIndex = 5;
    },
    /**
     * 设置影像是否加载
     * @param {Object}  data     影像数据
     * @param {Boolean} flag    是否加载
     */
    checkSheetChange(data, flag) {
        let id = data.gid + '_check';
        let index = dataJson.checkedSheetMap.indexOf(id);
        if (index === -1 && flag) {
            let positions = data.geom
                .replace('MULTIPOLYGON(((', '')
                .replace(')))', '')
                .split(',');
            for (let i = 0; i < positions.length; ++i) {
                let p = positions[i].split(' ');
                positions[i] = Cesium.Cartesian3.fromDegrees(Number(p[0]), Number(p[1]));
            }
            viewer.entities.add({
                id: id,
                polygon: {
                    arcType: Cesium.ArcType.RHUMB,
                    hierarchy: positions,
                    width: 2,
                    material: Cesium.Color.YELLOW.withAlpha(0.3),
                },
            });
            dataJson.checkedSheetMap.push(id);
        }
        if (index !== -1 && !flag) {
            viewer.entities.removeById(id);
            dataJson.checkedSheetMap.splice(index, 1);
        }
    },
    /**
     * 清空所有已选择的影像
     */
    clearAllSelectImage(key) {
        for (let i = 0; i < dataJson[key].length; ++i) {
            viewer.entities.removeById(dataJson[key][i]);
        }
        dataJson[key].length = 0;
    },

    createAdministrativeDivisions(data) {
        this.clearToolArea();
        if (!data) return;
        let geo = data.jsonObject;
        let entity = null;
        let color = Cesium.Color.fromCssColorString('rgba(253, 128, 69, 1.0)');
        Cesium.GeoJsonDataSource.load(geo).then(dataSource => {
            for (let i = 0; i < dataSource.entities.values.length; ++i) {
                entity = dataSource.entities.values[i];
                if (!entity.polygon) continue;
                entity.polygon = new Cesium.PolygonGraphics({
                    arcType: Cesium.ArcType.RHUMB,
                    hierarchy: entity.polygon.hierarchy,
                    outline: false,
                    material: color.withAlpha(0.2),
                    classificationType: Cesium.ClassificationType.TERRAIN,
                });
                entity.polyline = new Cesium.PolylineGraphics({
                    positions: [
                        ...entity.polygon.hierarchy._value.positions,
                        entity.polygon.hierarchy._value.positions[0],
                    ],
                    width: 3,
                    material: color,
                    clampToGround: true,
                    classificationType: Cesium.ClassificationType.TERRAIN,
                    zIndex: 0,
                });
                let holes = entity.polygon.hierarchy._value.holes;
                for (let j = 0; j < holes.length; ++j) {
                    dataSource.entities.add({
                        polyline: {
                            positions: [...holes[j].positions, holes[j].positions[0]],
                            width: 3,
                            clampToGround: true,
                            material: color,
                            classificationType: Cesium.ClassificationType.TERRAIN,
                            zIndex: 0,
                        },
                    });
                }
            }
            viewer.dataSources.add(dataSource);

            viewer.zoomTo(dataSource, new Cesium.HeadingPitchRange(0, -Math.PI / 2, 0));
            dataJson.administrativeDivisions = dataSource;
        });
    },
    clearToolArea() {
        // 清空绘制区域
        viewer.entities.removeById('target');
        // 清空矢量区域
        viewer.dataSources.remove(dataJson.administrativeDivisions);
        dataJson.administrativeDivisions = null;
    },
    clearAreaAddCurrentPage() {
        viewer.dataSources.remove(dataJson.dataArea);
        dataJson.dataArea = null;
        for (let i = 0; i < dataJson.currentPageData.length; ++i) {
            viewer.entities.removeById(dataJson.currentPageData[i]);
        }
        dataJson.currentPageData.length = 0;
    },
    calculationGeoJsonBox(json) {
        if (!json || !json.features || json.features.length < 1) {
            return;
        }
        let box = bbox(json);
        return [
            {
                longitude: Math.max(Math.min(180, box[0]), -180),
                latitude: Math.max(Math.min(90, box[1]), -90),
            },
            {
                longitude: Math.max(Math.min(180, box[0]), -180),
                latitude: Math.max(Math.min(90, box[3]), -90),
            },
            {
                longitude: Math.max(Math.min(180, box[2]), -180),
                latitude: Math.max(Math.min(90, box[3]), -90),
            },
            {
                longitude: Math.max(Math.min(180, box[2]), -180),
                latitude: Math.max(Math.min(90, box[1]), -90),
            },
        ];
    },
};
